package com.webank.wedatasphere.qualitis.controller.thymeleaf;

import com.webank.wedatasphere.qualitis.handler.CommonExcelService;
import com.webank.wedatasphere.qualitis.project.dao.repository.ProjectFileRepository;
import com.webank.wedatasphere.qualitis.project.dao.repository.ProjectMenuRepository;
import com.webank.wedatasphere.qualitis.project.dao.repository.ProjectRepository;
import com.webank.wedatasphere.qualitis.project.entity.Project;
import com.webank.wedatasphere.qualitis.project.entity.ProjectFile;
import com.webank.wedatasphere.qualitis.project.entity.ProjectMenu;
import com.webank.wedatasphere.qualitis.response.BiaoZunExcelDTO;
import com.webank.wedatasphere.qualitis.response.Resp;
import com.webank.wedatasphere.qualitis.response.RuleDetailDTO;
import com.webank.wedatasphere.qualitis.rule.dao.repository.RuleDetailInfoVoRepository;
import com.webank.wedatasphere.qualitis.rule.dao.repository.SqlTaskRepository;
import com.webank.wedatasphere.qualitis.rule.entity.RuleDetailInfoVo;
import com.webank.wedatasphere.qualitis.rule.entity.SqlTaskInfo;
import com.webank.wedatasphere.qualitis.util.CreateTreeUtils;
import com.webank.wedatasphere.qualitis.util.LocalTimeUtils;
import com.webank.wedatasphere.qualitis.util.WordUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.util.*;

@RestController
public class CommonController {

    private Logger logger =  LoggerFactory.getLogger(CommonController.class);
    /**
     * 菜单实现
     */
    @Autowired
    private ProjectMenuRepository projectMenuRepository;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 菜单实现
     */
    @Autowired
    private ProjectFileRepository projectFileRepository;


    private String fileSavePath;

    @Autowired
    private Environment environment;

    @Autowired
    private CommonExcelService commonExcelService;

    @PostConstruct
    public void loadEvn() {
        // 切换代码执行环境
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            fileSavePath = environment.getProperty("file.save.path_windows");
        } else {
            fileSavePath = environment.getProperty("file.save.path_linux");
        }
    }

    @RequestMapping(value = {"/getMenuList"}, method = RequestMethod.GET, name = "获取菜单列表·")
    @ResponseBody
    public Resp<?> getMenuList(HttpServletRequest request) {
        List<ProjectMenu> all = projectMenuRepository.findAll();
        List<ProjectMenu> tree = CreateTreeUtils.createTree(all);
        // 生成目录树
        return Resp.Ok(tree);
    }


    /**
     * 菜单目录
     *
     * @return
     */
    @RequestMapping(value = {"/menuIndex"}, method = RequestMethod.GET)
    public ModelAndView menuIndex() {
        ModelAndView modelAndView = new ModelAndView("layui-admin/index2");
        List<ProjectMenu> all = projectMenuRepository.findAll();
        List<ProjectMenu> tree = CreateTreeUtils.createTree(all);
        modelAndView.addObject("resourceGroups", tree);
        return modelAndView;
    }

    /**
     * 导入
     *
     * @param request  request
     * @param response response
     */
    @RequestMapping(value = {"/insertFile"}, method = {RequestMethod.GET, RequestMethod.POST}, name = "文件上传·")
    @ResponseBody
    public Resp<?> insertFile(HttpServletRequest request, HttpServletResponse response, @RequestParam("file") MultipartFile multipartFile) {
        String originalFilename = multipartFile.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)) {
            return Resp.error("文件名不能为空");
        }
        // 校验目录库
        String currentTime = LocalTimeUtils.getCurrentTimeSimple();
        File file = new File(fileSavePath + "/" + currentTime);
        if (!file.isDirectory()) {
            file.mkdirs();
        }
        String filePath = "";
        // 文件保留路径
        String fileName = fileSavePath + "/" + currentTime + "/" + originalFilename;
        File dest = new File(fileName);
        ProjectFile projectFile = new ProjectFile();
        try {
            // 保存本地文件
            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), dest);
            // 文件回调组装入库
            filePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/" + fileName;
            // 文件上传到目录库
            projectFile.setFileName(originalFilename);
            projectFile.setFilePath(fileName);
            projectFile.setName(filePath);
            projectFile.setCreateTime(currentTime);
            projectFileRepository.save(projectFile);
        } catch (Exception e) {
            e.printStackTrace();
            return Resp.error(e.getMessage());
        }
        // 返回文件路径
        return Resp.Ok(projectFile);
    }

    /**
     * 导入数据库
     *
     * @param request  request
     * @param response response
     */
    @RequestMapping(value = {"/excelSaveDb"}, method = {RequestMethod.GET, RequestMethod.POST}, name = "文件上传·")
    @ResponseBody
    public Resp<?> excelSaveDb(HttpServletRequest request, HttpServletResponse response, @RequestParam("file") MultipartFile multipartFile) {
        String originalFilename = multipartFile.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)) {
            return Resp.error("文件名不能为空");
        }
        if (!originalFilename.contains(".xls")) {
            return Resp.error("文件格式错误:必须要是XLS或者XLSX格式");
        }
        // 校验目录库
        String currentTime = LocalTimeUtils.getCurrentTimeSimple();
        File file = new File(fileSavePath + "/" + currentTime);
        if (!file.isDirectory()) {
            file.mkdirs();
        }
        String filePath = "";
        // 文件保留路径
        String fileName = fileSavePath + "/" + currentTime + "/" + originalFilename;
        File dest = new File(fileName);
        ProjectFile projectFile = new ProjectFile();
        try {
            // 保存本地文件
            FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), dest);
            // 文件回调组装入库
            filePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/" + fileName;
            // 文件上传到目录库
            projectFile.setFileName(originalFilename);
            projectFile.setFilePath(fileName);
            projectFile.setName(filePath);
            projectFile.setCreateTime(currentTime);
            projectFileRepository.save(projectFile);
        } catch (Exception e) {
            e.printStackTrace();
            return Resp.error(e.getMessage());
        }
        // 读取成为Excel入库
        commonExcelService.handlerBiaoZunUpload(fileName);
        // 返回文件路径
        return Resp.Ok(projectFile);
    }

    /**
     * 导出
     *
     * @param request  request
     * @param response response
     */
    @RequestMapping(value = "/downloadFile", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public ResponseEntity<Resource> export(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        String fileId = request.getParameter("fileId");
        if (StringUtils.isNotBlank(fileId)) {
            ProjectFile one = projectFileRepository.getOne(Long.parseLong(fileId));
            String filePath = one.getFilePath();
            String fileName = one.getFileName();
            // 创建FileSystemResource对象
            Resource resource = new FileSystemResource(Paths.get(filePath).toFile());
            // 设置响应头信息
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
            // 返回文件作为响应体
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);

        }
        return ResponseEntity.ok().body(null);
    }

    /**
     * 导出Excel
     *
     * @param projects request
     * @param response response
     */
    @RequestMapping(value = "/exportExcel", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public void exportExcel(HttpServletResponse response, @RequestBody List<Project> projects) throws IOException {
        List<BiaoZunExcelDTO> list = new ArrayList<>(projects.size());
        for (Project project : projects) {
            BiaoZunExcelDTO biaoZunExcelDTO = new BiaoZunExcelDTO();
            biaoZunExcelDTO.setSjzlbzml(project.getSjzlbzml());
            biaoZunExcelDTO.setCnName(project.getCnName());
            biaoZunExcelDTO.setCkwx(project.getCkwx());
            biaoZunExcelDTO.setSyfw(project.getSyfw());
            biaoZunExcelDTO.setFbzt(project.getFbzt());
            biaoZunExcelDTO.setSjzllx(project.getSjzllx());
            list.add(biaoZunExcelDTO);
        }
        // 导出数据位Excel
        commonExcelService.handlerBiaoZunDownload(response.getOutputStream(), list);
    }

    /**
     * 导出Word
     *
     * @param response response
     */
    @RequestMapping(value = "/exportWordByHTML", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public void exportWordByHTML(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String projectId = request.getParameter("projectId");
        String sort = request.getParameter("sort");
        // HTML转Word
        ResponseEntity<String> forEntity = restTemplate.getForEntity("http://localhost:8090/qa/sqlTask/taskInfoView?projectId=" + projectId + "&sort=" + sort, String.class);
        // 导出Word
        try {
            WordUtil.exportWord(request, response, forEntity.getBody().replace("\n",""), "biaoZun");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Autowired
    private ProjectRepository projectRepository;

    @Autowired
    private SqlTaskRepository sqlTaskRepository;

    @Autowired
    private RuleDetailInfoVoRepository ruleDetailInfoVoRepository;


    /**
     * 导出Word
     *
     * @param response response
     */
    @RequestMapping(value = "/exportWord", method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public void exportWord(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String projectId = request.getParameter("projectId");
        String sort = request.getParameter("sort");
        try {
            Project one = projectRepository.getOne(Long.parseLong(projectId));
            // 展示数据质量标准任务执行情况的信息
            List<SqlTaskInfo> sqlTaskInfos = sqlTaskRepository.findByProjectIdAndSort(projectId, Integer.parseInt(sort));
            if (CollectionUtils.isEmpty(sqlTaskInfos)){
                logger.error("未查询到数据质量标准任务执行情况的信息");
                return;
            }
            long ruleSuccess = sqlTaskInfos.stream().filter(sqlTaskInfo -> sqlTaskInfo.getCheckStatus().equals("校验通过")).count();
            String endTime = sqlTaskInfos.stream().max(Comparator.comparing(SqlTaskInfo::getId)).get().getEndTime();
            Map<String,Object> map = new HashMap<>();
            map.put("ruleSuccess", ruleSuccess);
            map.put("ruleFail", sqlTaskInfos.size() - ruleSuccess);
            map.put("ruleTotal", sqlTaskInfos.size());
            map.put("beginTime",sqlTaskInfos.get(0).getBeginTime());
            map.put("endTime", endTime);
            List<RuleDetailDTO> ruleDetailDTOS = new ArrayList<>();
            // 查询规则相关的信息
            for (SqlTaskInfo taskInfo : sqlTaskInfos) {
                // 获取规则信息
                RuleDetailInfoVo ruleDetailInfoVo = ruleDetailInfoVoRepository.findById(taskInfo.getRuleNewId()).get();
                RuleDetailDTO ruleDetailDTO = new RuleDetailDTO();
                ruleDetailDTO.setRuleName(ruleDetailInfoVo.getRuleName());
                ruleDetailDTO.setRuleTemplate(ruleDetailInfoVo.getRuleTemplate());
                ruleDetailDTO.setRuleType(ruleDetailInfoVo.getRuleType());
                ruleDetailDTO.setCheckStatus(taskInfo.getCheckStatus());
                ruleDetailDTO.setDatabaseName(ruleDetailInfoVo.getDatabaseName());
                ruleDetailDTO.setFieldName(ruleDetailInfoVo.getFieldName());
                ruleDetailDTO.setTableName(ruleDetailInfoVo.getTableName());
                ruleDetailDTO.setDataSourceEngine(ruleDetailInfoVo.getDataSourceEngine());
                String desc = "期望执行结果是：" + ruleDetailInfoVo.getCompareType() +" "+ ruleDetailInfoVo.getCheckThreshold();
                ruleDetailDTO.setDesc(desc);
                ruleDetailDTOS.add(ruleDetailDTO);
            }
            if (CollectionUtils.isEmpty(ruleDetailDTOS)){
                logger.error("导出Word失败，规则详情为空");
                return;
            }
            // 导出Word
            XWPFDocument document = WordUtil.generateWordXWPFDocument(one,ruleDetailDTOS,map);
            response.reset();
            request.setCharacterEncoding("utf-8");
            response.setContentType("application/msword");
            response.setHeader("Content-disposition",
                    "attachment;filename="+ new String(one.getCnName().getBytes("GB2312"),"iso8859-1")+ LocalTimeUtils.getCurrentTimeSimple() + ".docx");
            OutputStream os = response.getOutputStream();
            document.write(os);
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
